const express = require("express");
const cors = require("cors");
const WebSocket = require("ws");
const bodyParser = require("body-parser");
const fileUpload = require("express-fileupload");
const { join } = require("path");
const { existsSync } = require("fs");
const { writeTomlFile } = require("./utils/frpHelper");
const {
  startFrpc,
  stopFrpc,
  getFrpcLogs,
  getStatus,
  getVersion,
  downloadLocalVersion,
} = require("./utils/frpcManager");
const {
  readConfig,
  writeConfig,
  exportConfig,
  importConfig,
  appendProxyToConfig,
} = require("./utils/configManager");
const path = require("path");
const fs = require("fs");

const app = express();
const PORT = 3001;

app.use(cors());
app.use(bodyParser.json());
app.use(fileUpload());

/**初始化 WebSocket 服务（例如监听 3002 端口） */
const wss = new WebSocket.Server({ port: 3002 });
let clients = [];

/**连接WebSocket */
wss.on("connection", (ws) => {
  clients.push(ws);

  ws.on("close", () => {
    clients = clients.filter((c) => c !== ws);
  });
});

/**保存配置，生成INI文件 */
app.post("/generate-ini", (req, res) => {
  try {
    const path = writeTomlFile(req.body);
    res.send({ success: true, path, message: "INI 文件生成成功" });
  } catch (err) {
    res.status(500).send({ error: err.message });
  }
});
/**启动frpc */
app.post("/start-frp", async (req, res) => {
  try {
    await startFrpc(req.body, (log) => {
      clients.forEach((c) => c.readyState === WebSocket.OPEN && c.send(log));
    });
    res.json({ message: "frpc 启动成功" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

/**停止frpc */
app.post("/stop-frp", (req, res) => {
  try {
    stopFrpc();
    res.json({ message: "frpc 已停止" });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});
/**过去日志 */
app.get("/frp-logs", (req, res) => {
  res.send({ logs: getFrpcLogs() });
});

// 检查 frpc.exe 是否存在
app.post("/check-frpc", (req, res) => {
  const { frp_path } = req.body;
  const exePath = join(frp_path, "frpc.exe");
  const exists = existsSync(exePath);
  res.send({ exists });
});
/**获取代理列表 */
app.get("/api/proxies", (req, res) => {
  const frpPath = req.query.frp_path;
  if (!frpPath) return res.status(400).json({ error: "缺少 frp_path 参数" });
  const config = readConfig(frpPath);
  const proxies = Object.entries(config)
    .filter(([section]) => section !== "common")
    .map(([name, details]) => ({ name, ...details }));
  res.json(proxies);
});
/**添加代理 */
app.post("/api/proxies", (req, res) => {
  const frpPath = req.query.frp_path;
  const { name, ...proxyData } = req.body;

  if (!frpPath || !name) {
    return res.status(400).json({ message: "缺少 frp_path 或 name" });
  }

  try {
    const config = readConfig(frpPath);

    if (!config.common) {
      return res.status(400).json({
        message: "[common] 段缺失，请先配置全局连接参数",
      });
    }
    if (config[name]) {
      return res.status(400).json({
        message: "代理名称重复",
      });
    }

    appendProxyToConfig(frpPath, name, proxyData);
    res.json({ message: "添加成功，并已写入文件" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
/**更新代理 */
app.put("/api/proxies/", (req, res) => {
  const frpPath = req.query.frp_path;
  if (!frpPath) return res.status(400).json({ error: "缺少 frp_path 参数" });

  const config = readConfig(frpPath);
  const oldName = req.query.oldName;
  const { name: newName, ...newConfig } = req.body;

  if (!newName) return res.status(400).json({ error: "缺少新的 name 字段" });
  if (!config[oldName]) return res.status(404).json({ error: "原配置不存在" });

  const newConfigObj = {};

  // common 保留在最前
  if (config.common) newConfigObj.common = config.common;

  for (const [key, val] of Object.entries(config)) {
    if (key === "common") continue;
    if (key === oldName) {
      newConfigObj[newName] = newConfig; // 插入修改后的项
    } else {
      newConfigObj[key] = val; // 其他项原样保留
    }
  }

  writeConfig(frpPath, newConfigObj);
  res.json({ message: "更新成功" });
});
/**删除代理 */
app.delete("/api/proxies/:name", (req, res) => {
  const frpPath = req.query.frp_path;
  if (!frpPath) return res.status(400).json({ error: "缺少 frp_path 参数" });
  const config = readConfig(frpPath);
  delete config[req.params.name];
  writeConfig(frpPath, config);
  res.json({ message: "删除成功" });
});
/**导出配置 */
app.get("/api/export", (req, res) => {
  const frpPath = req.query.frp_path;
  if (!frpPath) return res.status(400).json({ error: "缺少 frp_path 参数" });

  try {
    const content = exportConfig(frpPath);
    res.setHeader("Content-Disposition", 'attachment; filename="frpc.toml"');
    res.setHeader("Content-Type", "text/plain; charset=utf-8");
    res.send(content);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

/**导入 TOML 文件：上传并覆盖 frpc.toml */
// app.post('/api/import', upload.single('file'), (req, res) => {
//   const frpPath = req.query.frp_path
//   if (!frpPath) return res.status(400).json({ error: '缺少 frp_path 参数' })

//   try {
//     const rawContent = req.file.buffer.toString('utf-8')

//     // 验证是否合法 TOML
//     const parsed = toml.parse(rawContent)

//     const targetPath = path.join(frpPath, 'frpc.toml')
//     fs.writeFileSync(targetPath, rawContent, 'utf-8')

//     res.json({ message: '配置导入成功', parsed })
//   } catch (err) {
//     res.status(400).json({ error: 'TOML 格式不合法或写入失败', detail: err.message })
//   }
// })
/**获取状态 */
app.get("/frp-status", (req, res) => {
  const status = getStatus();
  res.json(status);
});

// 获取本地版本列表
app.get("/api/local-versions", async (req, res) => {
  try {
    const versions = await getVersion();
    res.json(versions);
  } catch (err) {
    console.error("获取本地版本列表失败:", err);
    res.status(500).json({ error: "获取本地版本列表失败" });
  }
});
// 下载本地版本文件接口
app.get("/api/local-versions/download", async (req, res) => {
  const { filename } = req.query;
  // 安全验证：确保文件名符合预期格式，防止路径遍历攻击
  if (!filename || !/^frp_[\d.]+_windows_\w+\.zip$/.test(filename)) {
    return res.status(400).send("无效的文件名");
  }
  const LOCAL_VERSIONS_DIR = path.join(__dirname, "public", "versions");
  const filePath = path.join(LOCAL_VERSIONS_DIR, filename);
  try {
    // 检查文件是否存在（使用 fs.promises 进行异步检查）
    await fs.promises.access(filePath);

    // 设置响应头，指定为附件下载
    res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
    res.setHeader("Content-Type", "application/octet-stream");

    // 使用 fs.createReadStream 创建可读流（注意这里用的是 fs，不是 fs.promises）
    const readStream = fs.createReadStream(filePath);
    readStream.pipe(res);
  } catch (error) {
    console.error("下载文件失败:", error);
    res.status(404).send("文件不存在或无法访问");
  }
});

app.listen(PORT, () => {
  console.log(`FRP 后端已启动：http://localhost:${PORT}`);
});
